| File: | var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/cxxalloc.h |
| Warning: | line 60, column 10 Attempt to free released memory |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |||
| 2 | /* vim:expandtab:shiftwidth=2:tabstop=2: | |||
| 3 | */ | |||
| 4 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
| 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
| 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
| 7 | ||||
| 8 | #include "nsGNOMEShellSearchProvider.h" | |||
| 9 | ||||
| 10 | #include "nsToolkitCompsCID.h" | |||
| 11 | #include "nsIFaviconService.h" | |||
| 12 | #include "base/message_loop.h" // for MessageLoop | |||
| 13 | #include "base/task.h" // for NewRunnableMethod, etc | |||
| 14 | #include "mozilla/gfx/2D.h" | |||
| 15 | #include "nsComponentManagerUtils.h" | |||
| 16 | #include "nsIIOService.h" | |||
| 17 | #include "nsIURI.h" | |||
| 18 | #include "nsNetCID.h" | |||
| 19 | #include "nsPrintfCString.h" | |||
| 20 | #include "nsServiceManagerUtils.h" | |||
| 21 | #include "mozilla/GUniquePtr.h" | |||
| 22 | #include "mozilla/UniquePtrExtensions.h" | |||
| 23 | ||||
| 24 | #include "imgIContainer.h" | |||
| 25 | #include "imgITools.h" | |||
| 26 | ||||
| 27 | using namespace mozilla; | |||
| 28 | using namespace mozilla::gfx; | |||
| 29 | ||||
| 30 | // Mozilla has old GIO version in build roots | |||
| 31 | #define G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUEGBusNameOwnerFlags(1 << 2) GBusNameOwnerFlags(1 << 2) | |||
| 32 | ||||
| 33 | static const char* introspect_template = | |||
| 34 | "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection " | |||
| 35 | "1.0//EN\"\n" | |||
| 36 | "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n" | |||
| 37 | "<node>\n" | |||
| 38 | " <interface name=\"org.gnome.Shell.SearchProvider2\">\n" | |||
| 39 | " <method name=\"GetInitialResultSet\">\n" | |||
| 40 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
| 41 | " <arg type=\"as\" name=\"results\" direction=\"out\" />\n" | |||
| 42 | " </method>\n" | |||
| 43 | " <method name=\"GetSubsearchResultSet\">\n" | |||
| 44 | " <arg type=\"as\" name=\"previous_results\" direction=\"in\" />\n" | |||
| 45 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
| 46 | " <arg type=\"as\" name=\"results\" direction=\"out\" />\n" | |||
| 47 | " </method>\n" | |||
| 48 | " <method name=\"GetResultMetas\">\n" | |||
| 49 | " <arg type=\"as\" name=\"identifiers\" direction=\"in\" />\n" | |||
| 50 | " <arg type=\"aa{sv}\" name=\"metas\" direction=\"out\" />\n" | |||
| 51 | " </method>\n" | |||
| 52 | " <method name=\"ActivateResult\">\n" | |||
| 53 | " <arg type=\"s\" name=\"identifier\" direction=\"in\" />\n" | |||
| 54 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
| 55 | " <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n" | |||
| 56 | " </method>\n" | |||
| 57 | " <method name=\"LaunchSearch\">\n" | |||
| 58 | " <arg type=\"as\" name=\"terms\" direction=\"in\" />\n" | |||
| 59 | " <arg type=\"u\" name=\"timestamp\" direction=\"in\" />\n" | |||
| 60 | " </method>\n" | |||
| 61 | "</interface>\n" | |||
| 62 | "</node>\n"; | |||
| 63 | ||||
| 64 | class AsyncFaviconDataReady final : public nsIFaviconDataCallback { | |||
| 65 | public: | |||
| 66 | NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID , void** aInstancePtr) override; virtual MozExternalRefCountType AddRef(void) override; virtual MozExternalRefCountType Release (void) override; using HasThreadSafeRefCnt = std::false_type; protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread ; public: | |||
| 67 | NS_DECL_NSIFAVICONDATACALLBACKvirtual nsresult OnComplete(nsIURI *aFaviconURI, uint32_t aDataLen , const uint8_t *aData, const nsACString& aMimeType, uint16_t aWidth) override; | |||
| 68 | ||||
| 69 | AsyncFaviconDataReady(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult, | |||
| 70 | int aIconIndex, int aTimeStamp) | |||
| 71 | : mSearchResult(std::move(aSearchResult)), | |||
| 72 | mIconIndex(aIconIndex), | |||
| 73 | mTimeStamp(aTimeStamp) {}; | |||
| 74 | ||||
| 75 | private: | |||
| 76 | ~AsyncFaviconDataReady() {} | |||
| 77 | ||||
| 78 | RefPtr<nsGNOMEShellHistorySearchResult> mSearchResult; | |||
| 79 | int mIconIndex; | |||
| 80 | int mTimeStamp; | |||
| 81 | }; | |||
| 82 | ||||
| 83 | NS_IMPL_ISUPPORTS(AsyncFaviconDataReady, nsIFaviconDataCallback)MozExternalRefCountType AsyncFaviconDataReady::AddRef(void) { static_assert(!std::is_destructible_v<AsyncFaviconDataReady >, "Reference-counted class " "AsyncFaviconDataReady" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 83; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("AsyncFaviconDataReady" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("AsyncFaviconDataReady" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"AsyncFaviconDataReady\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"AsyncFaviconDataReady\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 83; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("AsyncFaviconDataReady" " not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), ("AsyncFaviconDataReady" ), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType AsyncFaviconDataReady::Release(void) { do { static_assert( mozilla ::detail::AssertionConditionType<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect (!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false ); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 83 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); do { static_assert( mozilla::detail::AssertionConditionType <decltype("AsyncFaviconDataReady" != nullptr)>::isValid , "invalid assertion condition"); if ((__builtin_expect(!!(!( !!("AsyncFaviconDataReady" != nullptr))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("\"AsyncFaviconDataReady\" != nullptr" " (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"AsyncFaviconDataReady\" != nullptr" ") (" "Must specify a name" ")"); do { *((volatile int*)__null ) = 83; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership ("AsyncFaviconDataReady" " not thread-safe"); const char* const nametmp = "AsyncFaviconDataReady"; nsrefcnt count = --mRefCnt ; NS_LogRelease((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return 0; } return count; } nsresult AsyncFaviconDataReady::QueryInterface(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak (NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!" , "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 83); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE ; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE" ); static const QITableEntry table[] = { {&mozilla::detail ::kImplementedIID<AsyncFaviconDataReady, nsIFaviconDataCallback >, int32_t( reinterpret_cast<char*>(static_cast<nsIFaviconDataCallback *>((AsyncFaviconDataReady*)0x1000)) - reinterpret_cast< char*>((AsyncFaviconDataReady*)0x1000))}, {&mozilla::detail ::kImplementedIID<AsyncFaviconDataReady, nsISupports>, int32_t (reinterpret_cast<char*>(static_cast<nsISupports*> ( static_cast<nsIFaviconDataCallback*>((AsyncFaviconDataReady *)0x1000))) - reinterpret_cast<char*>((AsyncFaviconDataReady *)0x1000))}, { nullptr, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID, aInstancePtr , table); return rv; } | |||
| 84 | ||||
| 85 | // Inspired by SurfaceToPackedBGRA | |||
| 86 | static UniquePtr<uint8_t[]> SurfaceToPackedRGBA(DataSourceSurface* aSurface) { | |||
| 87 | IntSize size = aSurface->GetSize(); | |||
| 88 | CheckedInt<size_t> bufferSize = | |||
| 89 | CheckedInt<size_t>(size.width * 4) * CheckedInt<size_t>(size.height); | |||
| 90 | if (!bufferSize.isValid()) { | |||
| 91 | return nullptr; | |||
| 92 | } | |||
| 93 | UniquePtr<uint8_t[]> imageBuffer(new (std::nothrow) | |||
| 94 | uint8_t[bufferSize.value()]); | |||
| 95 | if (!imageBuffer) { | |||
| 96 | return nullptr; | |||
| 97 | } | |||
| 98 | ||||
| 99 | DataSourceSurface::MappedSurface map; | |||
| 100 | if (!aSurface->Map(DataSourceSurface::MapType::READ, &map)) { | |||
| 101 | return nullptr; | |||
| 102 | } | |||
| 103 | ||||
| 104 | // Convert BGRA to RGBA | |||
| 105 | uint32_t* aSrc = (uint32_t*)map.mData; | |||
| 106 | uint32_t* aDst = (uint32_t*)imageBuffer.get(); | |||
| 107 | for (int i = 0; i < size.width * size.height; i++, aDst++, aSrc++) { | |||
| 108 | *aDst = *aSrc & 0xff00ff00; | |||
| 109 | *aDst |= (*aSrc & 0xff) << 16; | |||
| 110 | *aDst |= (*aSrc & 0xff0000) >> 16; | |||
| 111 | } | |||
| 112 | ||||
| 113 | aSurface->Unmap(); | |||
| 114 | ||||
| 115 | return imageBuffer; | |||
| 116 | } | |||
| 117 | ||||
| 118 | NS_IMETHODIMPnsresult | |||
| 119 | AsyncFaviconDataReady::OnComplete(nsIURI* aFaviconURI, uint32_t aDataLen, | |||
| 120 | const uint8_t* aData, | |||
| 121 | const nsACString& aMimeType, | |||
| 122 | uint16_t aWidth) { | |||
| 123 | // This is a callback from some previous search so we don't want it | |||
| 124 | if (mTimeStamp != mSearchResult->GetTimeStamp() || !aData || !aDataLen) { | |||
| 125 | return NS_ERROR_FAILURE; | |||
| 126 | } | |||
| 127 | ||||
| 128 | // Decode the image from the format it was returned to us in (probably PNG) | |||
| 129 | nsCOMPtr<imgIContainer> container; | |||
| 130 | nsCOMPtr<imgITools> imgtool = do_CreateInstance("@mozilla.org/image/tools;1"); | |||
| 131 | nsresult rv = imgtool->DecodeImageFromBuffer( | |||
| 132 | reinterpret_cast<const char*>(aData), aDataLen, aMimeType, | |||
| 133 | getter_AddRefs(container)); | |||
| 134 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 134); return rv; } } while (false); | |||
| 135 | ||||
| 136 | RefPtr<SourceSurface> surface = container->GetFrame( | |||
| 137 | imgIContainer::FRAME_FIRST, | |||
| 138 | imgIContainer::FLAG_SYNC_DECODE | imgIContainer::FLAG_ASYNC_NOTIFY); | |||
| 139 | ||||
| 140 | if (!surface || surface->GetFormat() != SurfaceFormat::B8G8R8A8) { | |||
| 141 | return NS_ERROR_FAILURE; | |||
| 142 | } | |||
| 143 | ||||
| 144 | // Allocate a new buffer that we own. | |||
| 145 | RefPtr<DataSourceSurface> dataSurface = surface->GetDataSurface(); | |||
| 146 | UniquePtr<uint8_t[]> data = SurfaceToPackedRGBA(dataSurface); | |||
| 147 | if (!data) { | |||
| 148 | return NS_ERROR_OUT_OF_MEMORY; | |||
| 149 | } | |||
| 150 | ||||
| 151 | mSearchResult->SetHistoryIcon(mTimeStamp, std::move(data), | |||
| 152 | surface->GetSize().width, | |||
| 153 | surface->GetSize().height, mIconIndex); | |||
| 154 | return NS_OK; | |||
| 155 | } | |||
| 156 | ||||
| 157 | void nsGNOMEShellSearchProvider::HandleSearchResultSet( | |||
| 158 | GVariant* aParameters, GDBusMethodInvocation* aInvocation, | |||
| 159 | bool aInitialSearch) { | |||
| 160 | // Discard any existing search results. | |||
| 161 | mSearchResult = nullptr; | |||
| 162 | ||||
| 163 | RefPtr<nsGNOMEShellHistorySearchResult> newSearch = | |||
| 164 | new nsGNOMEShellHistorySearchResult(this, mConnection, | |||
| 165 | mSearchResultTimeStamp); | |||
| 166 | mSearchResultTimeStamp++; | |||
| 167 | newSearch->SetTimeStamp(mSearchResultTimeStamp); | |||
| 168 | ||||
| 169 | // Send the search request over DBus. We'll get reply over DBus it will be | |||
| 170 | // set to mSearchResult by nsGNOMEShellSearchProvider::SetSearchResult(). | |||
| 171 | DBusHandleResultSet(newSearch.forget(), aParameters, aInitialSearch, | |||
| 172 | aInvocation); | |||
| 173 | } | |||
| 174 | ||||
| 175 | void nsGNOMEShellSearchProvider::HandleResultMetas( | |||
| 176 | GVariant* aParameters, GDBusMethodInvocation* aInvocation) { | |||
| 177 | if (mSearchResult) { | |||
| 178 | DBusHandleResultMetas(mSearchResult, aParameters, aInvocation); | |||
| 179 | } | |||
| 180 | } | |||
| 181 | ||||
| 182 | void nsGNOMEShellSearchProvider::ActivateResult( | |||
| 183 | GVariant* aParameters, GDBusMethodInvocation* aInvocation) { | |||
| 184 | if (mSearchResult) { | |||
| 185 | DBusActivateResult(mSearchResult, aParameters, aInvocation); | |||
| 186 | } | |||
| 187 | } | |||
| 188 | ||||
| 189 | void nsGNOMEShellSearchProvider::LaunchSearch( | |||
| 190 | GVariant* aParameters, GDBusMethodInvocation* aInvocation) { | |||
| 191 | if (mSearchResult) { | |||
| 192 | DBusLaunchSearch(mSearchResult, aParameters, aInvocation); | |||
| 193 | } | |||
| 194 | } | |||
| 195 | ||||
| 196 | static void HandleMethodCall(GDBusConnection* aConnection, const gchar* aSender, | |||
| 197 | const gchar* aObjectPath, | |||
| 198 | const gchar* aInterfaceName, | |||
| 199 | const gchar* aMethodName, GVariant* aParameters, | |||
| 200 | GDBusMethodInvocation* aInvocation, | |||
| 201 | gpointer aUserData) { | |||
| 202 | MOZ_ASSERT(aUserData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aUserData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aUserData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aUserData", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 202); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUserData" ")" ); do { *((volatile int*)__null) = 202; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 203 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 203); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 203; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 204 | ||||
| 205 | if (strcmp("org.gnome.Shell.SearchProvider2", aInterfaceName) == 0) { | |||
| 206 | if (strcmp("GetInitialResultSet", aMethodName) == 0) { | |||
| 207 | static_cast<nsGNOMEShellSearchProvider*>(aUserData) | |||
| 208 | ->HandleSearchResultSet(aParameters, aInvocation, | |||
| 209 | /* aInitialSearch */ true); | |||
| 210 | } else if (strcmp("GetSubsearchResultSet", aMethodName) == 0) { | |||
| 211 | static_cast<nsGNOMEShellSearchProvider*>(aUserData) | |||
| 212 | ->HandleSearchResultSet(aParameters, aInvocation, | |||
| 213 | /* aInitialSearch */ false); | |||
| 214 | } else if (strcmp("GetResultMetas", aMethodName) == 0) { | |||
| 215 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->HandleResultMetas( | |||
| 216 | aParameters, aInvocation); | |||
| 217 | } else if (strcmp("ActivateResult", aMethodName) == 0) { | |||
| 218 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->ActivateResult( | |||
| 219 | aParameters, aInvocation); | |||
| 220 | } else if (strcmp("LaunchSearch", aMethodName) == 0) { | |||
| 221 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->LaunchSearch( | |||
| 222 | aParameters, aInvocation); | |||
| 223 | } else { | |||
| 224 | g_warning( | |||
| 225 | "nsGNOMEShellSearchProvider: HandleMethodCall() wrong method %s", | |||
| 226 | aMethodName); | |||
| 227 | } | |||
| 228 | } | |||
| 229 | } | |||
| 230 | ||||
| 231 | static GVariant* HandleGetProperty(GDBusConnection* aConnection, | |||
| 232 | const gchar* aSender, | |||
| 233 | const gchar* aObjectPath, | |||
| 234 | const gchar* aInterfaceName, | |||
| 235 | const gchar* aPropertyName, GError** aError, | |||
| 236 | gpointer aUserData) { | |||
| 237 | MOZ_ASSERT(aUserData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aUserData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aUserData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aUserData", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 237); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUserData" ")" ); do { *((volatile int*)__null) = 237; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 238 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 238; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 239 | g_set_error(aError, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_FAILED, | |||
| 240 | "%s:%s setting is not supported", aInterfaceName, aPropertyName); | |||
| 241 | return nullptr; | |||
| 242 | } | |||
| 243 | ||||
| 244 | static gboolean HandleSetProperty(GDBusConnection* aConnection, | |||
| 245 | const gchar* aSender, | |||
| 246 | const gchar* aObjectPath, | |||
| 247 | const gchar* aInterfaceName, | |||
| 248 | const gchar* aPropertyName, GVariant* aValue, | |||
| 249 | GError** aError, gpointer aUserData) { | |||
| 250 | MOZ_ASSERT(aUserData)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aUserData)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aUserData))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aUserData", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aUserData" ")" ); do { *((volatile int*)__null) = 250; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 251 | MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType< decltype(NS_IsMainThread())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 251); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { *((volatile int*)__null) = 251; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 252 | g_set_error(aError, G_IO_ERRORg_io_error_quark(), G_IO_ERROR_FAILED, | |||
| 253 | "%s:%s setting is not supported", aInterfaceName, aPropertyName); | |||
| 254 | return false; | |||
| 255 | } | |||
| 256 | ||||
| 257 | static const GDBusInterfaceVTable gInterfaceVTable = { | |||
| 258 | HandleMethodCall, HandleGetProperty, HandleSetProperty}; | |||
| 259 | ||||
| 260 | void nsGNOMEShellSearchProvider::OnBusAcquired(GDBusConnection* aConnection) { | |||
| 261 | GUniquePtr<GError> error; | |||
| 262 | mIntrospectionData = dont_AddRef(g_dbus_node_info_new_for_xml( | |||
| 263 | introspect_template, getter_Transfers(error))); | |||
| 264 | if (!mIntrospectionData) { | |||
| 265 | g_warning( | |||
| 266 | "nsGNOMEShellSearchProvider: g_dbus_node_info_new_for_xml() failed! %s", | |||
| 267 | error->message); | |||
| 268 | return; | |||
| 269 | } | |||
| 270 | ||||
| 271 | mRegistrationId = g_dbus_connection_register_object( | |||
| 272 | aConnection, GetDBusObjectPath(), mIntrospectionData->interfaces[0], | |||
| 273 | &gInterfaceVTable, this, /* user_data */ | |||
| 274 | nullptr, /* user_data_free_func */ | |||
| 275 | getter_Transfers(error)); /* GError** */ | |||
| 276 | ||||
| 277 | if (mRegistrationId == 0) { | |||
| 278 | g_warning( | |||
| 279 | "nsGNOMEShellSearchProvider: g_dbus_connection_register_object() " | |||
| 280 | "failed! %s", | |||
| 281 | error->message); | |||
| 282 | return; | |||
| 283 | } | |||
| 284 | } | |||
| 285 | ||||
| 286 | void nsGNOMEShellSearchProvider::OnNameAcquired(GDBusConnection* aConnection) { | |||
| 287 | mConnection = aConnection; | |||
| 288 | } | |||
| 289 | ||||
| 290 | void nsGNOMEShellSearchProvider::OnNameLost(GDBusConnection* aConnection) { | |||
| 291 | mConnection = nullptr; | |||
| 292 | if (!mRegistrationId) { | |||
| 293 | return; | |||
| 294 | } | |||
| 295 | if (g_dbus_connection_unregister_object(aConnection, mRegistrationId)) { | |||
| 296 | mRegistrationId = 0; | |||
| 297 | } | |||
| 298 | } | |||
| 299 | ||||
| 300 | nsresult nsGNOMEShellSearchProvider::Startup() { | |||
| 301 | if (mDBusID) { | |||
| 302 | // We're already connected so we don't need to reconnect | |||
| 303 | return NS_ERROR_ALREADY_INITIALIZED; | |||
| 304 | } | |||
| 305 | ||||
| 306 | mDBusID = g_bus_own_name( | |||
| 307 | G_BUS_TYPE_SESSION, GetDBusBusName(), G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUEGBusNameOwnerFlags(1 << 2), | |||
| 308 | [](GDBusConnection* aConnection, const gchar*, | |||
| 309 | gpointer aUserData) -> void { | |||
| 310 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnBusAcquired( | |||
| 311 | aConnection); | |||
| 312 | }, | |||
| 313 | [](GDBusConnection* aConnection, const gchar*, | |||
| 314 | gpointer aUserData) -> void { | |||
| 315 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnNameAcquired( | |||
| 316 | aConnection); | |||
| 317 | }, | |||
| 318 | [](GDBusConnection* aConnection, const gchar*, | |||
| 319 | gpointer aUserData) -> void { | |||
| 320 | static_cast<nsGNOMEShellSearchProvider*>(aUserData)->OnNameLost( | |||
| 321 | aConnection); | |||
| 322 | }, | |||
| 323 | this, nullptr); | |||
| 324 | ||||
| 325 | if (!mDBusID) { | |||
| 326 | g_warning("nsGNOMEShellSearchProvider: g_bus_own_name() failed!"); | |||
| 327 | return NS_ERROR_FAILURE; | |||
| 328 | } | |||
| 329 | ||||
| 330 | mSearchResultTimeStamp = 0; | |||
| 331 | return NS_OK; | |||
| 332 | } | |||
| 333 | ||||
| 334 | void nsGNOMEShellSearchProvider::Shutdown() { | |||
| 335 | OnNameLost(mConnection); | |||
| 336 | if (mDBusID) { | |||
| 337 | g_bus_unown_name(mDBusID); | |||
| 338 | mDBusID = 0; | |||
| 339 | } | |||
| 340 | mIntrospectionData = nullptr; | |||
| 341 | } | |||
| 342 | ||||
| 343 | bool nsGNOMEShellSearchProvider::SetSearchResult( | |||
| 344 | RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult) { | |||
| 345 | MOZ_ASSERT(!mSearchResult)do { static_assert( mozilla::detail::AssertionConditionType< decltype(!mSearchResult)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(!mSearchResult))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mSearchResult" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 345); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mSearchResult" ")"); do { *((volatile int*)__null) = 345; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 346 | ||||
| 347 | if (mSearchResultTimeStamp != aSearchResult->GetTimeStamp()) { | |||
| 348 | NS_WARNING("Time stamp mismatch.")NS_DebugBreak(NS_DEBUG_WARNING, "Time stamp mismatch.", nullptr , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 348); | |||
| 349 | return false; | |||
| 350 | } | |||
| 351 | mSearchResult = aSearchResult; | |||
| 352 | return true; | |||
| 353 | } | |||
| 354 | ||||
| 355 | static void DispatchSearchResults( | |||
| 356 | RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult, | |||
| 357 | nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer) { | |||
| 358 | aSearchResult->ReceiveSearchResultContainer(aHistResultContainer); | |||
| 359 | } | |||
| 360 | ||||
| 361 | nsresult nsGNOMEShellHistoryService::QueryHistory( | |||
| 362 | RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult) { | |||
| 363 | if (!mHistoryService) { | |||
| 364 | mHistoryService = do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID"@mozilla.org/browser/nav-history-service;1"); | |||
| 365 | if (!mHistoryService) { | |||
| 366 | return NS_ERROR_FAILURE; | |||
| 367 | } | |||
| 368 | } | |||
| 369 | ||||
| 370 | nsresult rv; | |||
| 371 | nsCOMPtr<nsINavHistoryQuery> histQuery; | |||
| 372 | rv = mHistoryService->GetNewQuery(getter_AddRefs(histQuery)); | |||
| 373 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 373); return rv; } } while (false); | |||
| 374 | ||||
| 375 | rv = histQuery->SetSearchTerms( | |||
| 376 | NS_ConvertUTF8toUTF16(aSearchResult->GetSearchTerm())); | |||
| 377 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 377); return rv; } } while (false); | |||
| 378 | ||||
| 379 | nsCOMPtr<nsINavHistoryQueryOptions> histQueryOpts; | |||
| 380 | rv = mHistoryService->GetNewQueryOptions(getter_AddRefs(histQueryOpts)); | |||
| 381 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 381); return rv; } } while (false); | |||
| 382 | ||||
| 383 | rv = histQueryOpts->SetSortingMode( | |||
| 384 | nsINavHistoryQueryOptions::SORT_BY_FRECENCY_DESCENDING); | |||
| 385 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 385); return rv; } } while (false); | |||
| 386 | ||||
| 387 | rv = histQueryOpts->SetMaxResults(MAX_SEARCH_RESULTS_NUM9); | |||
| 388 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 388); return rv; } } while (false); | |||
| 389 | ||||
| 390 | nsCOMPtr<nsINavHistoryResult> histResult; | |||
| 391 | rv = mHistoryService->ExecuteQuery(histQuery, histQueryOpts, | |||
| 392 | getter_AddRefs(histResult)); | |||
| 393 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 393); return rv; } } while (false); | |||
| 394 | ||||
| 395 | nsCOMPtr<nsINavHistoryContainerResultNode> resultContainer; | |||
| 396 | ||||
| 397 | rv = histResult->GetRoot(getter_AddRefs(resultContainer)); | |||
| 398 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 398); return rv; } } while (false); | |||
| 399 | ||||
| 400 | rv = resultContainer->SetContainerOpen(true); | |||
| 401 | NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl (__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName (__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with " "result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t >(__rv), name ? " (" : "", name ? name : "", name ? ")" : "" ); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 401); return rv; } } while (false); | |||
| 402 | ||||
| 403 | // Simulate async searching by delayed reply. This search API will | |||
| 404 | // likely become async in the future and we want to be sure to not rely on | |||
| 405 | // its current synchronous behavior. | |||
| 406 | MOZ_ASSERT(MessageLoop::current())do { static_assert( mozilla::detail::AssertionConditionType< decltype(MessageLoop::current())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(MessageLoop::current()))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("MessageLoop::current()" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 406); AnnotateMozCrashReason("MOZ_ASSERT" "(" "MessageLoop::current()" ")"); do { *((volatile int*)__null) = 406; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 407 | MessageLoop::current()->PostTask( | |||
| 408 | NewRunnableFunction("Gnome shell search results", &DispatchSearchResults, | |||
| 409 | aSearchResult, resultContainer)); | |||
| 410 | ||||
| 411 | return NS_OK; | |||
| 412 | } | |||
| 413 | ||||
| 414 | static void DBusGetIDKeyForURI(int aIndex, nsAutoCString& aUri, | |||
| 415 | nsAutoCString& aIDKey) { | |||
| 416 | // Compose ID as NN:URL where NN is index to our current history | |||
| 417 | // result container. | |||
| 418 | aIDKey = nsPrintfCString("%.2d:%s", aIndex, aUri.get()); | |||
| 419 | } | |||
| 420 | ||||
| 421 | // Send (as) rearch result reply | |||
| 422 | void nsGNOMEShellHistorySearchResult::HandleSearchResultReply() { | |||
| 423 | MOZ_ASSERT(mReply)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mReply)>::isValid, "invalid assertion condition") ; if ((__builtin_expect(!!(!(!!(mReply))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mReply", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 423); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mReply" ")") ; do { *((volatile int*)__null) = 423; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 424 | ||||
| 425 | GVariantBuilder b; | |||
| 426 | g_variant_builder_init(&b, G_VARIANT_TYPE("as")(g_variant_type_checked_ (("as")))); | |||
| 427 | ||||
| 428 | uint32_t childCount = 0; | |||
| 429 | nsresult rv = mHistResultContainer->GetChildCount(&childCount); | |||
| 430 | if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && childCount > 0) { | |||
| 431 | // Obtain the favicon service and get the favicon for the specified page | |||
| 432 | nsCOMPtr<nsIFaviconService> favIconSvc( | |||
| 433 | do_GetService("@mozilla.org/browser/favicon-service;1")); | |||
| 434 | nsCOMPtr<nsIIOService> ios(do_GetService(NS_IOSERVICE_CONTRACTID"@mozilla.org/network/io-service;1")); | |||
| 435 | ||||
| 436 | if (childCount > MAX_SEARCH_RESULTS_NUM9) { | |||
| 437 | childCount = MAX_SEARCH_RESULTS_NUM9; | |||
| 438 | } | |||
| 439 | ||||
| 440 | for (uint32_t i = 0; i < childCount; i++) { | |||
| 441 | nsCOMPtr<nsINavHistoryResultNode> child; | |||
| 442 | rv = mHistResultContainer->GetChild(i, getter_AddRefs(child)); | |||
| 443 | if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv )), 0))), "NS_FAILED(rv)", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 443)) { | |||
| 444 | continue; | |||
| 445 | } | |||
| 446 | if (!IsHistoryResultNodeURI(child)) { | |||
| 447 | continue; | |||
| 448 | } | |||
| 449 | ||||
| 450 | nsAutoCString uri; | |||
| 451 | child->GetUri(uri); | |||
| 452 | ||||
| 453 | nsCOMPtr<nsIURI> iconIri; | |||
| 454 | ios->NewURI(uri, nullptr, nullptr, getter_AddRefs(iconIri)); | |||
| 455 | nsCOMPtr<nsIFaviconDataCallback> callback = | |||
| 456 | new AsyncFaviconDataReady(this, i, mTimeStamp); | |||
| 457 | favIconSvc->GetFaviconDataForPage(iconIri, callback, 0); | |||
| 458 | ||||
| 459 | nsAutoCString idKey; | |||
| 460 | DBusGetIDKeyForURI(i, uri, idKey); | |||
| 461 | ||||
| 462 | g_variant_builder_add(&b, "s", idKey.get()); | |||
| 463 | } | |||
| 464 | } | |||
| 465 | ||||
| 466 | nsPrintfCString searchString("%s:%s", KEYWORD_SEARCH_STRING"special:search", | |||
| 467 | mSearchTerm.get()); | |||
| 468 | g_variant_builder_add(&b, "s", searchString.get()); | |||
| 469 | ||||
| 470 | GVariant* v = g_variant_builder_end(&b); | |||
| 471 | g_dbus_method_invocation_return_value(mReply, g_variant_new_tuple(&v, 1)); | |||
| 472 | mReply = nullptr; | |||
| 473 | } | |||
| 474 | ||||
| 475 | void nsGNOMEShellHistorySearchResult::ReceiveSearchResultContainer( | |||
| 476 | nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer) { | |||
| 477 | // Propagate search results to nsGNOMEShellSearchProvider. | |||
| 478 | // SetSearchResult() checks this is up-to-date search (our time stamp matches | |||
| 479 | // latest requested search timestamp). | |||
| 480 | if (mSearchProvider->SetSearchResult(this)) { | |||
| 481 | mHistResultContainer = aHistResultContainer; | |||
| 482 | HandleSearchResultReply(); | |||
| 483 | } | |||
| 484 | } | |||
| 485 | ||||
| 486 | void nsGNOMEShellHistorySearchResult::SetHistoryIcon(int aTimeStamp, | |||
| 487 | UniquePtr<uint8_t[]> aData, | |||
| 488 | int aWidth, int aHeight, | |||
| 489 | int aIconIndex) { | |||
| 490 | MOZ_ASSERT(mTimeStamp == aTimeStamp)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mTimeStamp == aTimeStamp)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mTimeStamp == aTimeStamp))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mTimeStamp == aTimeStamp" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 490); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTimeStamp == aTimeStamp" ")"); do { *((volatile int*)__null) = 490; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| ||||
| 491 | MOZ_RELEASE_ASSERT(aIconIndex < MAX_SEARCH_RESULTS_NUM)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aIconIndex < 9)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aIconIndex < 9))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aIconIndex < 9" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 491); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "aIconIndex < 9" ")"); do { *((volatile int*)__null) = 491; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 492 | mHistoryIcons[aIconIndex].Set(mTimeStamp, std::move(aData), aWidth, aHeight); | |||
| 493 | } | |||
| 494 | ||||
| 495 | GnomeHistoryIcon* nsGNOMEShellHistorySearchResult::GetHistoryIcon( | |||
| 496 | int aIconIndex) { | |||
| 497 | MOZ_RELEASE_ASSERT(aIconIndex < MAX_SEARCH_RESULTS_NUM)do { static_assert( mozilla::detail::AssertionConditionType< decltype(aIconIndex < 9)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(aIconIndex < 9))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aIconIndex < 9" , "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.cpp" , 497); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "aIconIndex < 9" ")"); do { *((volatile int*)__null) = 497; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); | |||
| 498 | if (mHistoryIcons[aIconIndex].GetTimeStamp() == mTimeStamp && | |||
| 499 | mHistoryIcons[aIconIndex].IsLoaded()) { | |||
| 500 | return mHistoryIcons + aIconIndex; | |||
| 501 | } | |||
| 502 | return nullptr; | |||
| 503 | } | |||
| 504 | ||||
| 505 | nsGNOMEShellHistoryService* GetGNOMEShellHistoryService() { | |||
| 506 | static nsGNOMEShellHistoryService gGNOMEShellHistoryService; | |||
| 507 | return &gGNOMEShellHistoryService; | |||
| 508 | } |
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim:expandtab:shiftwidth=2:tabstop=2: |
| 3 | */ |
| 4 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 5 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 6 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 7 | |
| 8 | #ifndef __nsGNOMEShellSearchProvider_h__ |
| 9 | #define __nsGNOMEShellSearchProvider_h__ |
| 10 | |
| 11 | #include <gio/gio.h> |
| 12 | |
| 13 | #include "mozilla/RefPtr.h" |
| 14 | #include "mozilla/GRefPtr.h" |
| 15 | #include "mozilla/Span.h" |
| 16 | #include "nsINavHistoryService.h" |
| 17 | #include "nsUnixRemoteServer.h" |
| 18 | #include "nsString.h" |
| 19 | #include "nsCOMPtr.h" |
| 20 | #include "mozilla/UniquePtr.h" |
| 21 | #include "nsGNOMEShellDBusHelper.h" |
| 22 | |
| 23 | class nsGNOMEShellSearchProvider; |
| 24 | |
| 25 | class GnomeHistoryIcon { |
| 26 | public: |
| 27 | GnomeHistoryIcon() : mTimeStamp(-1), mWidth(0), mHeight(0) {}; |
| 28 | |
| 29 | // From which search is this icon |
| 30 | void Set(int aTimeStamp, mozilla::UniquePtr<uint8_t[]> aData, int aWidth, |
| 31 | int aHeight) { |
| 32 | mTimeStamp = aTimeStamp; |
| 33 | mWidth = aWidth; |
| 34 | mHeight = aHeight; |
| 35 | mData = std::move(aData); |
| 36 | } |
| 37 | |
| 38 | bool IsLoaded() { return mData && mWidth > 0 && mHeight > 0; } |
| 39 | int GetTimeStamp() { return mTimeStamp; } |
| 40 | uint8_t* GetData() { return mData.get(); } |
| 41 | int GetWidth() { return mWidth; } |
| 42 | int GetHeight() { return mHeight; } |
| 43 | |
| 44 | private: |
| 45 | int mTimeStamp; |
| 46 | mozilla::UniquePtr<uint8_t[]> mData; |
| 47 | int mWidth; |
| 48 | int mHeight; |
| 49 | }; |
| 50 | |
| 51 | // nsGNOMEShellHistorySearchResult is a container with contains search results |
| 52 | // which are files asynchronously by nsGNOMEShellHistoryService. |
| 53 | // The search results can be opened by Firefox then. |
| 54 | class nsGNOMEShellHistorySearchResult : public nsUnixRemoteServer { |
| 55 | public: |
| 56 | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsGNOMEShellHistorySearchResult)public: MozExternalRefCountType AddRef(void) { static_assert( !std::is_destructible_v<nsGNOMEShellHistorySearchResult> , "Reference-counted class " "nsGNOMEShellHistorySearchResult" " should not have a public destructor. " "Make this class's destructor non-public" ); do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.h" , 56); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 56; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this ), (count), ("nsGNOMEShellHistorySearchResult"), (uint32_t)(sizeof (*this))); return (nsrefcnt)count; } MozExternalRefCountType Release (void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/browser/components/shell/nsGNOMEShellSearchProvider.h" , 56); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 56 ; __attribute__((nomerge)) ::abort(); } while (false); } } while (false); nsrefcnt count = --mRefCnt; NS_LogRelease((this), ( count), ("nsGNOMEShellHistorySearchResult")); if (count == 0) { delete (this); return 0; } return count; } using HasThreadSafeRefCnt = std::true_type; protected: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; public: |
| 57 | |
| 58 | nsGNOMEShellHistorySearchResult(nsGNOMEShellSearchProvider* aSearchProvider, |
| 59 | GDBusConnection* aConnection, int aTimeStamp) |
| 60 | : mSearchProvider(aSearchProvider), |
| 61 | mConnection(aConnection), |
| 62 | mTimeStamp(aTimeStamp) {}; |
| 63 | |
| 64 | void SetReply(RefPtr<GDBusMethodInvocation> aReply) { |
| 65 | mReply = std::move(aReply); |
| 66 | } |
| 67 | void SetSearchTerm(const char* aSearchTerm) { |
| 68 | mSearchTerm = nsAutoCString(aSearchTerm); |
| 69 | } |
| 70 | GDBusConnection* GetDBusConnection() { return mConnection; } |
| 71 | void SetTimeStamp(int aTimeStamp) { mTimeStamp = aTimeStamp; } |
| 72 | int GetTimeStamp() { return mTimeStamp; } |
| 73 | nsAutoCString& GetSearchTerm() { return mSearchTerm; } |
| 74 | |
| 75 | // Receive (asynchronously) history search results from history service. |
| 76 | // This is called asynchronously by nsGNOMEShellHistoryService |
| 77 | // when we have search results available. |
| 78 | void ReceiveSearchResultContainer( |
| 79 | nsCOMPtr<nsINavHistoryContainerResultNode> aHistResultContainer); |
| 80 | |
| 81 | nsCOMPtr<nsINavHistoryContainerResultNode> GetSearchResultContainer() { |
| 82 | return mHistResultContainer; |
| 83 | } |
| 84 | void HandleCommandLine(mozilla::Span<const char> aBuffer, |
| 85 | uint32_t aTimestamp) { |
| 86 | nsUnixRemoteServer::HandleCommandLine(aBuffer, aTimestamp); |
| 87 | } |
| 88 | |
| 89 | void SetHistoryIcon(int aTimeStamp, mozilla::UniquePtr<uint8_t[]> aData, |
| 90 | int aWidth, int aHeight, int aIconIndex); |
| 91 | GnomeHistoryIcon* GetHistoryIcon(int aIconIndex); |
| 92 | |
| 93 | private: |
| 94 | void HandleSearchResultReply(); |
| 95 | |
| 96 | ~nsGNOMEShellHistorySearchResult() = default; |
| 97 | |
| 98 | private: |
| 99 | nsGNOMEShellSearchProvider* mSearchProvider; |
| 100 | nsCOMPtr<nsINavHistoryContainerResultNode> mHistResultContainer; |
| 101 | nsAutoCString mSearchTerm; |
| 102 | RefPtr<GDBusMethodInvocation> mReply; |
| 103 | GDBusConnection* mConnection = nullptr; |
| 104 | int mTimeStamp; |
| 105 | GnomeHistoryIcon mHistoryIcons[MAX_SEARCH_RESULTS_NUM9]; |
| 106 | }; |
| 107 | |
| 108 | class nsGNOMEShellHistoryService { |
| 109 | public: |
| 110 | nsresult QueryHistory(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult); |
| 111 | |
| 112 | private: |
| 113 | nsCOMPtr<nsINavHistoryService> mHistoryService; |
| 114 | }; |
| 115 | |
| 116 | class nsGNOMEShellSearchProvider { |
| 117 | public: |
| 118 | nsGNOMEShellSearchProvider() |
| 119 | : mConnection(nullptr), mSearchResultTimeStamp(0) {} |
| 120 | ~nsGNOMEShellSearchProvider() { Shutdown(); } |
| 121 | |
| 122 | nsresult Startup(); |
| 123 | void Shutdown(); |
| 124 | |
| 125 | void UnregisterDBusInterface(GDBusConnection* aConnection); |
| 126 | |
| 127 | bool SetSearchResult(RefPtr<nsGNOMEShellHistorySearchResult> aSearchResult); |
| 128 | |
| 129 | void HandleSearchResultSet(GVariant* aParameters, |
| 130 | GDBusMethodInvocation* aInvocation, |
| 131 | bool aInitialSearch); |
| 132 | void HandleResultMetas(GVariant* aParameters, |
| 133 | GDBusMethodInvocation* aInvocation); |
| 134 | void ActivateResult(GVariant* aParameters, |
| 135 | GDBusMethodInvocation* aInvocation); |
| 136 | void LaunchSearch(GVariant* aParameters, GDBusMethodInvocation* aInvocation); |
| 137 | |
| 138 | void OnBusAcquired(GDBusConnection* aConnection); |
| 139 | void OnNameAcquired(GDBusConnection* aConnection); |
| 140 | void OnNameLost(GDBusConnection* aConnection); |
| 141 | |
| 142 | private: |
| 143 | // The connection is owned by DBus library |
| 144 | uint mDBusID = 0; |
| 145 | uint mRegistrationId = 0; |
| 146 | GDBusConnection* mConnection = nullptr; |
| 147 | RefPtr<GDBusNodeInfo> mIntrospectionData; |
| 148 | |
| 149 | RefPtr<nsGNOMEShellHistorySearchResult> mSearchResult; |
| 150 | int mSearchResultTimeStamp; |
| 151 | }; |
| 152 | |
| 153 | nsGNOMEShellHistoryService* GetGNOMEShellHistoryService(); |
| 154 | |
| 155 | #endif // __nsGNOMEShellSearchProvider_h__ |
| 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 | |
| 7 | /* Smart pointer managing sole ownership of a resource. */ |
| 8 | |
| 9 | #ifndef mozilla_UniquePtr_h |
| 10 | #define mozilla_UniquePtr_h |
| 11 | |
| 12 | #include <memory> |
| 13 | #include <type_traits> |
| 14 | #include <utility> |
| 15 | |
| 16 | #include "mozilla/Assertions.h" |
| 17 | #include "mozilla/Attributes.h" |
| 18 | #include "mozilla/CompactPair.h" |
| 19 | #include "mozilla/Compiler.h" |
| 20 | |
| 21 | namespace mozilla { |
| 22 | |
| 23 | template <typename T> |
| 24 | class DefaultDelete; |
| 25 | template <typename T, class D = DefaultDelete<T>> |
| 26 | class UniquePtr; |
| 27 | |
| 28 | } // namespace mozilla |
| 29 | |
| 30 | namespace mozilla { |
| 31 | |
| 32 | namespace detail { |
| 33 | |
| 34 | struct HasPointerTypeHelper { |
| 35 | template <class U> |
| 36 | static double Test(...); |
| 37 | template <class U> |
| 38 | static char Test(typename U::pointer* = 0); |
| 39 | }; |
| 40 | |
| 41 | template <class T> |
| 42 | class HasPointerType |
| 43 | : public std::integral_constant<bool, sizeof(HasPointerTypeHelper::Test<T>( |
| 44 | 0)) == 1> {}; |
| 45 | |
| 46 | template <class T, class D, bool = HasPointerType<D>::value> |
| 47 | struct PointerTypeImpl { |
| 48 | typedef typename D::pointer Type; |
| 49 | }; |
| 50 | |
| 51 | template <class T, class D> |
| 52 | struct PointerTypeImpl<T, D, false> { |
| 53 | typedef T* Type; |
| 54 | }; |
| 55 | |
| 56 | template <class T, class D> |
| 57 | struct PointerType { |
| 58 | typedef typename PointerTypeImpl<T, std::remove_reference_t<D>>::Type Type; |
| 59 | }; |
| 60 | |
| 61 | } // namespace detail |
| 62 | |
| 63 | /** |
| 64 | * UniquePtr is a smart pointer that wholly owns a resource. Ownership may be |
| 65 | * transferred out of a UniquePtr through explicit action, but otherwise the |
| 66 | * resource is destroyed when the UniquePtr is destroyed. |
| 67 | * |
| 68 | * UniquePtr is similar to C++98's std::auto_ptr, but it improves upon auto_ptr |
| 69 | * in one crucial way: it's impossible to copy a UniquePtr. Copying an auto_ptr |
| 70 | * obviously *can't* copy ownership of its singly-owned resource. So what |
| 71 | * happens if you try to copy one? Bizarrely, ownership is implicitly |
| 72 | * *transferred*, preserving single ownership but breaking code that assumes a |
| 73 | * copy of an object is identical to the original. (This is why auto_ptr is |
| 74 | * prohibited in STL containers.) |
| 75 | * |
| 76 | * UniquePtr solves this problem by being *movable* rather than copyable. |
| 77 | * Instead of passing a |UniquePtr u| directly to the constructor or assignment |
| 78 | * operator, you pass |Move(u)|. In doing so you indicate that you're *moving* |
| 79 | * ownership out of |u|, into the target of the construction/assignment. After |
| 80 | * the transfer completes, |u| contains |nullptr| and may be safely destroyed. |
| 81 | * This preserves single ownership but also allows UniquePtr to be moved by |
| 82 | * algorithms that have been made move-safe. (Note: if |u| is instead a |
| 83 | * temporary expression, don't use |Move()|: just pass the expression, because |
| 84 | * it's already move-ready. For more information see Move.h.) |
| 85 | * |
| 86 | * UniquePtr is also better than std::auto_ptr in that the deletion operation is |
| 87 | * customizable. An optional second template parameter specifies a class that |
| 88 | * (through its operator()(T*)) implements the desired deletion policy. If no |
| 89 | * policy is specified, mozilla::DefaultDelete<T> is used -- which will either |
| 90 | * |delete| or |delete[]| the resource, depending whether the resource is an |
| 91 | * array. Custom deletion policies ideally should be empty classes (no member |
| 92 | * fields, no member fields in base classes, no virtual methods/inheritance), |
| 93 | * because then UniquePtr can be just as efficient as a raw pointer. |
| 94 | * |
| 95 | * Use of UniquePtr proceeds like so: |
| 96 | * |
| 97 | * UniquePtr<int> g1; // initializes to nullptr |
| 98 | * g1.reset(new int); // switch resources using reset() |
| 99 | * g1 = nullptr; // clears g1, deletes the int |
| 100 | * |
| 101 | * UniquePtr<int> g2(new int); // owns that int |
| 102 | * int* p = g2.release(); // g2 leaks its int -- still requires deletion |
| 103 | * delete p; // now freed |
| 104 | * |
| 105 | * struct S { int x; S(int x) : x(x) {} }; |
| 106 | * UniquePtr<S> g3, g4(new S(5)); |
| 107 | * g3 = std::move(g4); // g3 owns the S, g4 cleared |
| 108 | * S* p = g3.get(); // g3 still owns |p| |
| 109 | * assert(g3->x == 5); // operator-> works (if .get() != nullptr) |
| 110 | * assert((*g3).x == 5); // also operator* (again, if not cleared) |
| 111 | * std::swap(g3, g4); // g4 now owns the S, g3 cleared |
| 112 | * g3.swap(g4); // g3 now owns the S, g4 cleared |
| 113 | * UniquePtr<S> g5(std::move(g3)); // g5 owns the S, g3 cleared |
| 114 | * g5.reset(); // deletes the S, g5 cleared |
| 115 | * |
| 116 | * struct FreePolicy { void operator()(void* p) { free(p); } }; |
| 117 | * UniquePtr<int, FreePolicy> g6(static_cast<int*>(malloc(sizeof(int)))); |
| 118 | * int* ptr = g6.get(); |
| 119 | * g6 = nullptr; // calls free(ptr) |
| 120 | * |
| 121 | * Now, carefully note a few things you *can't* do: |
| 122 | * |
| 123 | * UniquePtr<int> b1; |
| 124 | * b1 = new int; // BAD: can only assign another UniquePtr |
| 125 | * int* ptr = b1; // BAD: no auto-conversion to pointer, use get() |
| 126 | * |
| 127 | * UniquePtr<int> b2(b1); // BAD: can't copy a UniquePtr |
| 128 | * UniquePtr<int> b3 = b1; // BAD: can't copy-assign a UniquePtr |
| 129 | * |
| 130 | * (Note that changing a UniquePtr to store a direct |new| expression is |
| 131 | * permitted, but usually you should use MakeUnique, defined at the end of this |
| 132 | * header.) |
| 133 | * |
| 134 | * A few miscellaneous notes: |
| 135 | * |
| 136 | * UniquePtr, when not instantiated for an array type, can be move-constructed |
| 137 | * and move-assigned, not only from itself but from "derived" UniquePtr<U, E> |
| 138 | * instantiations where U converts to T and E converts to D. If you want to use |
| 139 | * this, you're going to have to specify a deletion policy for both UniquePtr |
| 140 | * instantations, and T pretty much has to have a virtual destructor. In other |
| 141 | * words, this doesn't work: |
| 142 | * |
| 143 | * struct Base { virtual ~Base() {} }; |
| 144 | * struct Derived : Base {}; |
| 145 | * |
| 146 | * UniquePtr<Base> b1; |
| 147 | * // BAD: DefaultDelete<Base> and DefaultDelete<Derived> don't interconvert |
| 148 | * UniquePtr<Derived> d1(std::move(b)); |
| 149 | * |
| 150 | * UniquePtr<Base> b2; |
| 151 | * UniquePtr<Derived, DefaultDelete<Base>> d2(std::move(b2)); // okay |
| 152 | * |
| 153 | * UniquePtr is specialized for array types. Specializing with an array type |
| 154 | * creates a smart-pointer version of that array -- not a pointer to such an |
| 155 | * array. |
| 156 | * |
| 157 | * UniquePtr<int[]> arr(new int[5]); |
| 158 | * arr[0] = 4; |
| 159 | * |
| 160 | * What else is different? Deletion of course uses |delete[]|. An operator[] |
| 161 | * is provided. Functionality that doesn't make sense for arrays is removed. |
| 162 | * The constructors and mutating methods only accept array pointers (not T*, U* |
| 163 | * that converts to T*, or UniquePtr<U[]> or UniquePtr<U>) or |nullptr|. |
| 164 | * |
| 165 | * It's perfectly okay for a function to return a UniquePtr. This transfers |
| 166 | * the UniquePtr's sole ownership of the data, to the fresh UniquePtr created |
| 167 | * in the calling function, that will then solely own that data. Such functions |
| 168 | * can return a local variable UniquePtr, |nullptr|, |UniquePtr(ptr)| where |
| 169 | * |ptr| is a |T*|, or a UniquePtr |Move()|'d from elsewhere. |
| 170 | * |
| 171 | * UniquePtr will commonly be a member of a class, with lifetime equivalent to |
| 172 | * that of that class. If you want to expose the related resource, you could |
| 173 | * expose a raw pointer via |get()|, but ownership of a raw pointer is |
| 174 | * inherently unclear. So it's better to expose a |const UniquePtr&| instead. |
| 175 | * This prohibits mutation but still allows use of |get()| when needed (but |
| 176 | * operator-> is preferred). Of course, you can only use this smart pointer as |
| 177 | * long as the enclosing class instance remains live -- no different than if you |
| 178 | * exposed the |get()| raw pointer. |
| 179 | * |
| 180 | * To pass a UniquePtr-managed resource as a pointer, use a |const UniquePtr&| |
| 181 | * argument. To specify an inout parameter (where the method may or may not |
| 182 | * take ownership of the resource, or reset it), or to specify an out parameter |
| 183 | * (where simply returning a |UniquePtr| isn't possible), use a |UniquePtr&| |
| 184 | * argument. To unconditionally transfer ownership of a UniquePtr |
| 185 | * into a method, use a |UniquePtr| argument. To conditionally transfer |
| 186 | * ownership of a resource into a method, should the method want it, use a |
| 187 | * |UniquePtr&&| argument. |
| 188 | */ |
| 189 | template <typename T, class D> |
| 190 | class UniquePtr { |
| 191 | public: |
| 192 | typedef T ElementType; |
| 193 | typedef D DeleterType; |
| 194 | typedef typename detail::PointerType<T, DeleterType>::Type Pointer; |
| 195 | |
| 196 | private: |
| 197 | mozilla::CompactPair<Pointer, DeleterType> mTuple; |
| 198 | |
| 199 | Pointer& ptr() { return mTuple.first(); } |
| 200 | const Pointer& ptr() const { return mTuple.first(); } |
| 201 | |
| 202 | DeleterType& del() { return mTuple.second(); } |
| 203 | const DeleterType& del() const { return mTuple.second(); } |
| 204 | |
| 205 | public: |
| 206 | /** |
| 207 | * Construct a UniquePtr containing |nullptr|. |
| 208 | */ |
| 209 | constexpr UniquePtr() : mTuple(static_cast<Pointer>(nullptr), DeleterType()) { |
| 210 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
| 211 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
| 212 | } |
| 213 | |
| 214 | /** |
| 215 | * Construct a UniquePtr containing |aPtr|. |
| 216 | */ |
| 217 | explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { |
| 218 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
| 219 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
| 220 | } |
| 221 | |
| 222 | UniquePtr(Pointer aPtr, |
| 223 | std::conditional_t<std::is_reference_v<D>, D, const D&> aD1) |
| 224 | : mTuple(aPtr, aD1) {} |
| 225 | |
| 226 | UniquePtr(Pointer aPtr, std::remove_reference_t<D>&& aD2) |
| 227 | : mTuple(aPtr, std::move(aD2)) { |
| 228 | static_assert(!std::is_reference_v<D>, |
| 229 | "rvalue deleter can't be stored by reference"); |
| 230 | } |
| 231 | |
| 232 | UniquePtr(UniquePtr&& aOther) |
| 233 | : mTuple(aOther.release(), |
| 234 | std::forward<DeleterType>(aOther.get_deleter())) {} |
| 235 | |
| 236 | MOZ_IMPLICIT constexpr UniquePtr(decltype(nullptr)) : UniquePtr() {} |
| 237 | |
| 238 | template <typename U, class E> |
| 239 | MOZ_IMPLICIT UniquePtr( |
| 240 | UniquePtr<U, E>&& aOther, |
| 241 | std::enable_if_t< |
| 242 | std::is_convertible_v<typename UniquePtr<U, E>::Pointer, Pointer> && |
| 243 | !std::is_array_v<U> && |
| 244 | (std::is_reference_v<D> ? std::is_same_v<D, E> |
| 245 | : std::is_convertible_v<E, D>), |
| 246 | int> |
| 247 | aDummy = 0) |
| 248 | : mTuple(aOther.release(), std::forward<E>(aOther.get_deleter())) {} |
| 249 | |
| 250 | ~UniquePtr() { reset(nullptr); } |
| 251 | |
| 252 | UniquePtr& operator=(UniquePtr&& aOther) { |
| 253 | reset(aOther.release()); |
| 254 | get_deleter() = std::forward<DeleterType>(aOther.get_deleter()); |
| 255 | return *this; |
| 256 | } |
| 257 | |
| 258 | template <typename U, typename E> |
| 259 | UniquePtr& operator=(UniquePtr<U, E>&& aOther) { |
| 260 | static_assert( |
| 261 | std::is_convertible_v<typename UniquePtr<U, E>::Pointer, Pointer>, |
| 262 | "incompatible UniquePtr pointees"); |
| 263 | static_assert(!std::is_array_v<U>, |
| 264 | "can't assign from UniquePtr holding an array"); |
| 265 | |
| 266 | reset(aOther.release()); |
| 267 | get_deleter() = std::forward<E>(aOther.get_deleter()); |
| 268 | return *this; |
| 269 | } |
| 270 | |
| 271 | UniquePtr& operator=(decltype(nullptr)) { |
| 272 | reset(nullptr); |
| 273 | return *this; |
| 274 | } |
| 275 | |
| 276 | std::add_lvalue_reference_t<T> operator*() const { |
| 277 | MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr with *")do { static_assert( mozilla::detail::AssertionConditionType< decltype(get())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(get()))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("get()" " (" "dereferencing a UniquePtr containing nullptr with *" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/UniquePtr.h" , 277); AnnotateMozCrashReason("MOZ_ASSERT" "(" "get()" ") (" "dereferencing a UniquePtr containing nullptr with *" ")"); do { *((volatile int*)__null) = 277; __attribute__((nomerge)) :: abort(); } while (false); } } while (false); |
| 278 | return *get(); |
| 279 | } |
| 280 | Pointer operator->() const { |
| 281 | MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr with ->")do { static_assert( mozilla::detail::AssertionConditionType< decltype(get())>::isValid, "invalid assertion condition"); if ((__builtin_expect(!!(!(!!(get()))), 0))) { do { } while ( false); MOZ_ReportAssertionFailure("get()" " (" "dereferencing a UniquePtr containing nullptr with ->" ")", "/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/mozilla/UniquePtr.h" , 281); AnnotateMozCrashReason("MOZ_ASSERT" "(" "get()" ") (" "dereferencing a UniquePtr containing nullptr with ->" ")" ); do { *((volatile int*)__null) = 281; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
| 282 | return get(); |
| 283 | } |
| 284 | |
| 285 | explicit operator bool() const { return get() != nullptr; } |
| 286 | |
| 287 | Pointer get() const { return ptr(); } |
| 288 | |
| 289 | DeleterType& get_deleter() { return del(); } |
| 290 | const DeleterType& get_deleter() const { return del(); } |
| 291 | |
| 292 | [[nodiscard]] Pointer release() { |
| 293 | Pointer p = ptr(); |
| 294 | ptr() = nullptr; |
| 295 | return p; |
| 296 | } |
| 297 | |
| 298 | void reset(Pointer aPtr = Pointer()) { |
| 299 | Pointer old = ptr(); |
| 300 | ptr() = aPtr; |
| 301 | if (old != nullptr) { |
| 302 | get_deleter()(old); |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } |
| 307 | |
| 308 | UniquePtr(const UniquePtr& aOther) = delete; // construct using std::move()! |
| 309 | void operator=(const UniquePtr& aOther) = |
| 310 | delete; // assign using std::move()! |
| 311 | }; |
| 312 | |
| 313 | // In case you didn't read the comment by the main definition (you should!): the |
| 314 | // UniquePtr<T[]> specialization exists to manage array pointers. It deletes |
| 315 | // such pointers using delete[], it will reject construction and modification |
| 316 | // attempts using U* or U[]. Otherwise it works like the normal UniquePtr. |
| 317 | template <typename T, class D> |
| 318 | class UniquePtr<T[], D> { |
| 319 | public: |
| 320 | typedef T* Pointer; |
| 321 | typedef T ElementType; |
| 322 | typedef D DeleterType; |
| 323 | |
| 324 | private: |
| 325 | mozilla::CompactPair<Pointer, DeleterType> mTuple; |
| 326 | |
| 327 | public: |
| 328 | /** |
| 329 | * Construct a UniquePtr containing nullptr. |
| 330 | */ |
| 331 | constexpr UniquePtr() : mTuple(static_cast<Pointer>(nullptr), DeleterType()) { |
| 332 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
| 333 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
| 334 | } |
| 335 | |
| 336 | /** |
| 337 | * Construct a UniquePtr containing |aPtr|. |
| 338 | */ |
| 339 | explicit UniquePtr(Pointer aPtr) : mTuple(aPtr, DeleterType()) { |
| 340 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
| 341 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
| 342 | } |
| 343 | |
| 344 | // delete[] knows how to handle *only* an array of a single class type. For |
| 345 | // delete[] to work correctly, it must know the size of each element, the |
| 346 | // fields and base classes of each element requiring destruction, and so on. |
| 347 | // So forbid all overloads which would end up invoking delete[] on a pointer |
| 348 | // of the wrong type. |
| 349 | template <typename U> |
| 350 | UniquePtr(U&& aU, |
| 351 | std::enable_if_t< |
| 352 | std::is_pointer_v<U> && std::is_convertible_v<U, Pointer>, int> |
| 353 | aDummy = 0) = delete; |
| 354 | |
| 355 | UniquePtr(Pointer aPtr, |
| 356 | std::conditional_t<std::is_reference_v<D>, D, const D&> aD1) |
| 357 | : mTuple(aPtr, aD1) {} |
| 358 | |
| 359 | UniquePtr(Pointer aPtr, std::remove_reference_t<D>&& aD2) |
| 360 | : mTuple(aPtr, std::move(aD2)) { |
| 361 | static_assert(!std::is_reference_v<D>, |
| 362 | "rvalue deleter can't be stored by reference"); |
| 363 | } |
| 364 | |
| 365 | // Forbidden for the same reasons as stated above. |
| 366 | template <typename U, typename V> |
| 367 | UniquePtr(U&& aU, V&& aV, |
| 368 | std::enable_if_t< |
| 369 | std::is_pointer_v<U> && std::is_convertible_v<U, Pointer>, int> |
| 370 | aDummy = 0) = delete; |
| 371 | |
| 372 | UniquePtr(UniquePtr&& aOther) |
| 373 | : mTuple(aOther.release(), |
| 374 | std::forward<DeleterType>(aOther.get_deleter())) {} |
| 375 | |
| 376 | MOZ_IMPLICIT |
| 377 | UniquePtr(decltype(nullptr)) : mTuple(nullptr, DeleterType()) { |
| 378 | static_assert(!std::is_pointer_v<D>, "must provide a deleter instance"); |
| 379 | static_assert(!std::is_reference_v<D>, "must provide a deleter instance"); |
| 380 | } |
| 381 | |
| 382 | ~UniquePtr() { reset(nullptr); } |
| 383 | |
| 384 | UniquePtr& operator=(UniquePtr&& aOther) { |
| 385 | reset(aOther.release()); |
| 386 | get_deleter() = std::forward<DeleterType>(aOther.get_deleter()); |
| 387 | return *this; |
| 388 | } |
| 389 | |
| 390 | UniquePtr& operator=(decltype(nullptr)) { |
| 391 | reset(); |
| 392 | return *this; |
| 393 | } |
| 394 | |
| 395 | explicit operator bool() const { return get() != nullptr; } |
| 396 | |
| 397 | T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; } |
| 398 | Pointer get() const { return mTuple.first(); } |
| 399 | |
| 400 | DeleterType& get_deleter() { return mTuple.second(); } |
| 401 | const DeleterType& get_deleter() const { return mTuple.second(); } |
| 402 | |
| 403 | [[nodiscard]] Pointer release() { |
| 404 | Pointer p = mTuple.first(); |
| 405 | mTuple.first() = nullptr; |
| 406 | return p; |
| 407 | } |
| 408 | |
| 409 | void reset(Pointer aPtr = Pointer()) { |
| 410 | Pointer old = mTuple.first(); |
| 411 | mTuple.first() = aPtr; |
| 412 | if (old != nullptr) { |
| 413 | mTuple.second()(old); |
| 414 | } |
| 415 | } |
| 416 | |
| 417 | void reset(decltype(nullptr)) { |
| 418 | Pointer old = mTuple.first(); |
| 419 | mTuple.first() = nullptr; |
| 420 | if (old != nullptr) { |
| 421 | mTuple.second()(old); |
| 422 | } |
| 423 | } |
| 424 | |
| 425 | template <typename U> |
| 426 | void reset(U) = delete; |
| 427 | |
| 428 | void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); } |
| 429 | |
| 430 | UniquePtr(const UniquePtr& aOther) = delete; // construct using std::move()! |
| 431 | void operator=(const UniquePtr& aOther) = |
| 432 | delete; // assign using std::move()! |
| 433 | }; |
| 434 | |
| 435 | /** |
| 436 | * A default deletion policy using plain old operator delete. |
| 437 | * |
| 438 | * Note that this type can be specialized, but authors should beware of the risk |
| 439 | * that the specialization may at some point cease to match (either because it |
| 440 | * gets moved to a different compilation unit or the signature changes). If the |
| 441 | * non-specialized (|delete|-based) version compiles for that type but does the |
| 442 | * wrong thing, bad things could happen. |
| 443 | * |
| 444 | * This is a non-issue for types which are always incomplete (i.e. opaque handle |
| 445 | * types), since |delete|-ing such a type will always trigger a compilation |
| 446 | * error. |
| 447 | */ |
| 448 | template <typename T> |
| 449 | class DefaultDelete { |
| 450 | public: |
| 451 | constexpr DefaultDelete() = default; |
| 452 | |
| 453 | template <typename U> |
| 454 | MOZ_IMPLICIT DefaultDelete( |
| 455 | const DefaultDelete<U>& aOther, |
| 456 | std::enable_if_t<std::is_convertible_v<U*, T*>, int> aDummy = 0) {} |
| 457 | |
| 458 | void operator()(T* aPtr) const { |
| 459 | static_assert(sizeof(T) > 0, "T must be complete"); |
| 460 | delete aPtr; |
| 461 | } |
| 462 | }; |
| 463 | |
| 464 | /** A default deletion policy using operator delete[]. */ |
| 465 | template <typename T> |
| 466 | class DefaultDelete<T[]> { |
| 467 | public: |
| 468 | constexpr DefaultDelete() = default; |
| 469 | |
| 470 | void operator()(T* aPtr) const { |
| 471 | static_assert(sizeof(T) > 0, "T must be complete"); |
| 472 | delete[] aPtr; |
| 473 | } |
| 474 | |
| 475 | template <typename U> |
| 476 | void operator()(U* aPtr) const = delete; |
| 477 | }; |
| 478 | |
| 479 | template <typename T, class D, typename U, class E> |
| 480 | bool operator==(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) { |
| 481 | return aX.get() == aY.get(); |
| 482 | } |
| 483 | |
| 484 | template <typename T, class D, typename U, class E> |
| 485 | bool operator!=(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY) { |
| 486 | return aX.get() != aY.get(); |
| 487 | } |
| 488 | |
| 489 | template <typename T, class D> |
| 490 | bool operator==(const UniquePtr<T, D>& aX, const T* aY) { |
| 491 | return aX.get() == aY; |
| 492 | } |
| 493 | |
| 494 | template <typename T, class D> |
| 495 | bool operator==(const T* aY, const UniquePtr<T, D>& aX) { |
| 496 | return aY == aX.get(); |
| 497 | } |
| 498 | |
| 499 | template <typename T, class D> |
| 500 | bool operator!=(const UniquePtr<T, D>& aX, const T* aY) { |
| 501 | return aX.get() != aY; |
| 502 | } |
| 503 | |
| 504 | template <typename T, class D> |
| 505 | bool operator!=(const T* aY, const UniquePtr<T, D>& aX) { |
| 506 | return aY != aX.get(); |
| 507 | } |
| 508 | |
| 509 | template <typename T, class D> |
| 510 | bool operator==(const UniquePtr<T, D>& aX, decltype(nullptr)) { |
| 511 | return !aX; |
| 512 | } |
| 513 | |
| 514 | template <typename T, class D> |
| 515 | bool operator==(decltype(nullptr), const UniquePtr<T, D>& aX) { |
| 516 | return !aX; |
| 517 | } |
| 518 | |
| 519 | template <typename T, class D> |
| 520 | bool operator!=(const UniquePtr<T, D>& aX, decltype(nullptr)) { |
| 521 | return bool(aX); |
| 522 | } |
| 523 | |
| 524 | template <typename T, class D> |
| 525 | bool operator!=(decltype(nullptr), const UniquePtr<T, D>& aX) { |
| 526 | return bool(aX); |
| 527 | } |
| 528 | |
| 529 | // No operator<, operator>, operator<=, operator>= for now because simplicity. |
| 530 | |
| 531 | namespace detail { |
| 532 | |
| 533 | template <typename T> |
| 534 | struct UniqueSelector { |
| 535 | typedef UniquePtr<T> SingleObject; |
| 536 | }; |
| 537 | |
| 538 | template <typename T> |
| 539 | struct UniqueSelector<T[]> { |
| 540 | typedef UniquePtr<T[]> UnknownBound; |
| 541 | }; |
| 542 | |
| 543 | template <typename T, decltype(sizeof(int)) N> |
| 544 | struct UniqueSelector<T[N]> { |
| 545 | typedef UniquePtr<T[N]> KnownBound; |
| 546 | }; |
| 547 | |
| 548 | } // namespace detail |
| 549 | |
| 550 | /** |
| 551 | * MakeUnique is a helper function for allocating new'd objects and arrays, |
| 552 | * returning a UniquePtr containing the resulting pointer. The semantics of |
| 553 | * MakeUnique<Type>(...) are as follows. |
| 554 | * |
| 555 | * If Type is an array T[n]: |
| 556 | * Disallowed, deleted, no overload for you! |
| 557 | * If Type is an array T[]: |
| 558 | * MakeUnique<T[]>(size_t) is the only valid overload. The pointer returned |
| 559 | * is as if by |new T[n]()|, which value-initializes each element. (If T |
| 560 | * isn't a class type, this will zero each element. If T is a class type, |
| 561 | * then roughly speaking, each element will be constructed using its default |
| 562 | * constructor. See C++11 [dcl.init]p7 for the full gory details.) |
| 563 | * If Type is non-array T: |
| 564 | * The arguments passed to MakeUnique<T>(...) are forwarded into a |
| 565 | * |new T(...)| call, initializing the T as would happen if executing |
| 566 | * |T(...)|. |
| 567 | * |
| 568 | * There are various benefits to using MakeUnique instead of |new| expressions. |
| 569 | * |
| 570 | * First, MakeUnique eliminates use of |new| from code entirely. If objects are |
| 571 | * only created through UniquePtr, then (assuming all explicit release() calls |
| 572 | * are safe, including transitively, and no type-safety casting funniness) |
| 573 | * correctly maintained ownership of the UniquePtr guarantees no leaks are |
| 574 | * possible. (This pays off best if a class is only ever created through a |
| 575 | * factory method on the class, using a private constructor.) |
| 576 | * |
| 577 | * Second, initializing a UniquePtr using a |new| expression requires repeating |
| 578 | * the name of the new'd type, whereas MakeUnique in concert with the |auto| |
| 579 | * keyword names it only once: |
| 580 | * |
| 581 | * UniquePtr<char> ptr1(new char()); // repetitive |
| 582 | * auto ptr2 = MakeUnique<char>(); // shorter |
| 583 | * |
| 584 | * Of course this assumes the reader understands the operation MakeUnique |
| 585 | * performs. In the long run this is probably a reasonable assumption. In the |
| 586 | * short run you'll have to use your judgment about what readers can be expected |
| 587 | * to know, or to quickly look up. |
| 588 | * |
| 589 | * Third, a call to MakeUnique can be assigned directly to a UniquePtr. In |
| 590 | * contrast you can't assign a pointer into a UniquePtr without using the |
| 591 | * cumbersome reset(). |
| 592 | * |
| 593 | * UniquePtr<char> p; |
| 594 | * p = new char; // ERROR |
| 595 | * p.reset(new char); // works, but fugly |
| 596 | * p = MakeUnique<char>(); // preferred |
| 597 | * |
| 598 | * (And third, although not relevant to Mozilla: MakeUnique is exception-safe. |
| 599 | * An exception thrown after |new T| succeeds will leak that memory, unless the |
| 600 | * pointer is assigned to an object that will manage its ownership. UniquePtr |
| 601 | * ably serves this function.) |
| 602 | */ |
| 603 | |
| 604 | template <typename T, typename... Args> |
| 605 | typename detail::UniqueSelector<T>::SingleObject MakeUnique(Args&&... aArgs) { |
| 606 | return UniquePtr<T>(new T(std::forward<Args>(aArgs)...)); |
| 607 | } |
| 608 | |
| 609 | template <typename T> |
| 610 | typename detail::UniqueSelector<T>::UnknownBound MakeUnique( |
| 611 | decltype(sizeof(int)) aN) { |
| 612 | using ArrayType = std::remove_extent_t<T>; |
| 613 | return UniquePtr<T>(new ArrayType[aN]()); |
| 614 | } |
| 615 | |
| 616 | template <typename T, typename... Args> |
| 617 | typename detail::UniqueSelector<T>::KnownBound MakeUnique(Args&&... aArgs) = |
| 618 | delete; |
| 619 | |
| 620 | /** |
| 621 | * WrapUnique is a helper function to transfer ownership from a raw pointer |
| 622 | * into a UniquePtr<T>. It can only be used with a single non-array type. |
| 623 | * |
| 624 | * It is generally used this way: |
| 625 | * |
| 626 | * auto p = WrapUnique(new char); |
| 627 | * |
| 628 | * It can be used when MakeUnique is not usable, for example, when the |
| 629 | * constructor you are using is private, or you want to use aggregate |
| 630 | * initialization. |
| 631 | */ |
| 632 | |
| 633 | template <typename T> |
| 634 | typename detail::UniqueSelector<T>::SingleObject WrapUnique(T* aPtr) { |
| 635 | return UniquePtr<T>(aPtr); |
| 636 | } |
| 637 | |
| 638 | } // namespace mozilla |
| 639 | |
| 640 | namespace std { |
| 641 | |
| 642 | template <typename T, class D> |
| 643 | void swap(mozilla::UniquePtr<T, D>& aX, mozilla::UniquePtr<T, D>& aY) { |
| 644 | aX.swap(aY); |
| 645 | } |
| 646 | |
| 647 | } // namespace std |
| 648 | |
| 649 | /** |
| 650 | TempPtrToSetter(UniquePtr<T>*) -> T**-ish |
| 651 | TempPtrToSetter(std::unique_ptr<T>*) -> T**-ish |
| 652 | |
| 653 | Make a temporary class to support assigning to UniquePtr/unique_ptr via passing |
| 654 | a pointer to the callee. |
| 655 | |
| 656 | Often, APIs will be shaped like this trivial example: |
| 657 | ``` |
| 658 | nsresult Foo::NewChildBar(Bar** out) { |
| 659 | if (!IsOk()) return NS_ERROR_FAILURE; |
| 660 | *out = new Bar(this); |
| 661 | return NS_OK; |
| 662 | } |
| 663 | ``` |
| 664 | |
| 665 | In order to make this work with unique ptrs, it's often either risky or |
| 666 | overwrought: |
| 667 | ``` |
| 668 | Bar* bar = nullptr; |
| 669 | const auto cleanup = MakeScopeExit([&]() { |
| 670 | if (bar) { |
| 671 | delete bar; |
| 672 | } |
| 673 | }); |
| 674 | if (FAILED(foo->NewChildBar(&bar)) { |
| 675 | // handle it |
| 676 | } |
| 677 | ``` |
| 678 | |
| 679 | ``` |
| 680 | UniquePtr<Bar> bar; |
| 681 | { |
| 682 | Bar* raw = nullptr; |
| 683 | const auto res = foo->NewChildBar(&bar); |
| 684 | bar.reset(raw); |
| 685 | if (FAILED(res) { |
| 686 | // handle it |
| 687 | } |
| 688 | } |
| 689 | ``` |
| 690 | TempPtrToSettable is a shorthand for the latter approach, allowing something |
| 691 | cleaner but also safe: |
| 692 | |
| 693 | ``` |
| 694 | UniquePtr<Bar> bar; |
| 695 | if (FAILED(foo->NewChildBar(TempPtrToSetter(&bar))) { |
| 696 | // handle it |
| 697 | } |
| 698 | ``` |
| 699 | */ |
| 700 | |
| 701 | namespace mozilla { |
| 702 | namespace detail { |
| 703 | |
| 704 | template <class T, class UniquePtrT> |
| 705 | class MOZ_TEMPORARY_CLASS TempPtrToSetterT final { |
| 706 | private: |
| 707 | UniquePtrT* const mDest; |
| 708 | T* mNewVal; |
| 709 | |
| 710 | public: |
| 711 | explicit TempPtrToSetterT(UniquePtrT* dest) |
| 712 | : mDest(dest), mNewVal(mDest->get()) {} |
| 713 | |
| 714 | operator T**() { return &mNewVal; } |
| 715 | |
| 716 | ~TempPtrToSetterT() { |
| 717 | if (mDest->get() != mNewVal) { |
| 718 | mDest->reset(mNewVal); |
| 719 | } |
| 720 | } |
| 721 | }; |
| 722 | |
| 723 | } // namespace detail |
| 724 | |
| 725 | template <class T, class Deleter> |
| 726 | auto TempPtrToSetter(UniquePtr<T, Deleter>* const p) { |
| 727 | return detail::TempPtrToSetterT<T, UniquePtr<T, Deleter>>{p}; |
| 728 | } |
| 729 | |
| 730 | template <class T, class Deleter> |
| 731 | auto TempPtrToSetter(std::unique_ptr<T, Deleter>* const p) { |
| 732 | return detail::TempPtrToSetterT<T, std::unique_ptr<T, Deleter>>{p}; |
| 733 | } |
| 734 | |
| 735 | } // namespace mozilla |
| 736 | |
| 737 | #endif /* mozilla_UniquePtr_h */ |
| 1 | /* This Source Code Form is subject to the terms of the Mozilla Public | |||
| 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |||
| 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |||
| 4 | ||||
| 5 | #ifndef mozilla_cxxalloc_h | |||
| 6 | #define mozilla_cxxalloc_h | |||
| 7 | ||||
| 8 | /* | |||
| 9 | * We implement the default operators new/delete as part of | |||
| 10 | * libmozalloc, replacing their definitions in libstdc++. The | |||
| 11 | * operator new* definitions in libmozalloc will never return a NULL | |||
| 12 | * pointer. | |||
| 13 | * | |||
| 14 | * Each operator new immediately below returns a pointer to memory | |||
| 15 | * that can be delete'd by any of | |||
| 16 | * | |||
| 17 | * (1) the matching infallible operator delete immediately below | |||
| 18 | * (2) the matching system |operator delete(void*, std::nothrow)| | |||
| 19 | * (3) the matching system |operator delete(void*) noexcept(false)| | |||
| 20 | * | |||
| 21 | * NB: these are declared |noexcept(false)|, though they will never | |||
| 22 | * throw that exception. This declaration is consistent with the rule | |||
| 23 | * that |::operator new() noexcept(false)| will never return NULL. | |||
| 24 | * | |||
| 25 | * NB: mozilla::fallible can be used instead of std::nothrow. | |||
| 26 | */ | |||
| 27 | ||||
| 28 | #ifndef MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline | |||
| 29 | # define MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline MFBT_API__attribute__((weak)) __attribute__((visibility("default"))) | |||
| 30 | #endif | |||
| 31 | ||||
| 32 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new(size_t size) noexcept(false) { | |||
| 33 | return moz_xmalloc(size); | |||
| 34 | } | |||
| 35 | ||||
| 36 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new(size_t size, | |||
| 37 | const std::nothrow_t&) noexcept(true) { | |||
| 38 | return malloc_implmalloc(size); | |||
| 39 | } | |||
| 40 | ||||
| 41 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new[](size_t size) noexcept(false) { | |||
| 42 | return moz_xmalloc(size); | |||
| 43 | } | |||
| 44 | ||||
| 45 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void* operator new[](size_t size, | |||
| 46 | const std::nothrow_t&) noexcept(true) { | |||
| 47 | return malloc_implmalloc(size); | |||
| 48 | } | |||
| 49 | ||||
| 50 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr) noexcept(true) { | |||
| 51 | return free_implfree(ptr); | |||
| 52 | } | |||
| 53 | ||||
| 54 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr, | |||
| 55 | const std::nothrow_t&) noexcept(true) { | |||
| 56 | return free_implfree(ptr); | |||
| 57 | } | |||
| 58 | ||||
| 59 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[](void* ptr) noexcept(true) { | |||
| 60 | return free_implfree(ptr); | |||
| ||||
| 61 | } | |||
| 62 | ||||
| 63 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[]( | |||
| 64 | void* ptr, const std::nothrow_t&) noexcept(true) { | |||
| 65 | return free_implfree(ptr); | |||
| 66 | } | |||
| 67 | ||||
| 68 | #if defined(XP_WIN) | |||
| 69 | // We provide the global sized delete overloads unconditionally because the | |||
| 70 | // MSVC runtime headers do, despite compiling with /Zc:sizedDealloc- | |||
| 71 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete(void* ptr, | |||
| 72 | size_t /*size*/) noexcept(true) { | |||
| 73 | return free_implfree(ptr); | |||
| 74 | } | |||
| 75 | ||||
| 76 | MOZALLOC_EXPORT_NEW__attribute__((always_inline)) inline void operator delete[](void* ptr, | |||
| 77 | size_t /*size*/) noexcept(true) { | |||
| 78 | return free_implfree(ptr); | |||
| 79 | } | |||
| 80 | #endif | |||
| 81 | ||||
| 82 | #endif /* mozilla_cxxalloc_h */ |